using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using ActiproSoftware.SyntaxEditor.Addons.Simple.Ast;

namespace ActiproSoftware.SyntaxEditor.Addons.Simple {

	#region Token IDs
	/// <summary>
	/// Contains the token IDs for the <c>Simple</c> language.
	/// </summary>
	public class SimpleTokenID {

		/// <summary>
		/// Returns the string-based key for the specified token ID.
		/// </summary>
		/// <param name="id">The token ID to examine.</param>
		public static string GetTokenKey(int id) {
			System.Reflection.FieldInfo[] fields = typeof(SimpleTokenID).GetFields();
			foreach (System.Reflection.FieldInfo field in fields) {
				if ((field.IsStatic) && (field.IsLiteral) && (id.Equals(field.GetValue(null))))
					return field.Name;
			}
			return null;
		}

		/// <summary>
		/// The Invalid token ID.
		/// </summary>
		public const int Invalid = 0;

		/// <summary>
		/// The DocumentEnd token ID.
		/// </summary>
		public const int DocumentEnd = 1;

		/// <summary>
		/// The LanguageTransitionStart token ID.
		/// </summary>
		public const int LanguageTransitionStart = 2;

		/// <summary>
		/// The LanguageTransitionEnd token ID.
		/// </summary>
		public const int LanguageTransitionEnd = 3;

		/// <summary>
		/// The Whitespace token ID.
		/// </summary>
		public const int Whitespace = 4;

		/// <summary>
		/// The LineTerminator token ID.
		/// </summary>
		public const int LineTerminator = 5;

		/// <summary>
		/// The SingleLineComment token ID.
		/// </summary>
		public const int SingleLineComment = 6;

		/// <summary>
		/// The MultiLineComment token ID.
		/// </summary>
		public const int MultiLineComment = 7;

		/// <summary>
		/// The Number token ID.
		/// </summary>
		public const int Number = 8;

		/// <summary>
		/// The Identifier token ID.
		/// </summary>
		public const int Identifier = 9;

		/// <summary>
		/// The KeywordStart token ID.
		/// </summary>
		public const int KeywordStart = 10;

		/// <summary>
		/// The Function token ID.
		/// </summary>
		public const int Function = 11;

		/// <summary>
		/// The Var token ID.
		/// </summary>
		public const int Var = 12;

		/// <summary>
		/// The Return token ID.
		/// </summary>
		public const int Return = 13;

		/// <summary>
		/// The KeywordEnd token ID.
		/// </summary>
		public const int KeywordEnd = 14;

		/// <summary>
		/// The OperatorOrPunctuatorStart token ID.
		/// </summary>
		public const int OperatorOrPunctuatorStart = 15;

		/// <summary>
		/// The OpenCurlyBrace token ID.
		/// </summary>
		public const int OpenCurlyBrace = 16;

		/// <summary>
		/// The CloseCurlyBrace token ID.
		/// </summary>
		public const int CloseCurlyBrace = 17;

		/// <summary>
		/// The OpenParenthesis token ID.
		/// </summary>
		public const int OpenParenthesis = 18;

		/// <summary>
		/// The CloseParenthesis token ID.
		/// </summary>
		public const int CloseParenthesis = 19;

		/// <summary>
		/// The Comma token ID.
		/// </summary>
		public const int Comma = 20;

		/// <summary>
		/// The SemiColon token ID.
		/// </summary>
		public const int SemiColon = 21;

		/// <summary>
		/// The Addition token ID.
		/// </summary>
		public const int Addition = 22;

		/// <summary>
		/// The Subtraction token ID.
		/// </summary>
		public const int Subtraction = 23;

		/// <summary>
		/// The Multiplication token ID.
		/// </summary>
		public const int Multiplication = 24;

		/// <summary>
		/// The Division token ID.
		/// </summary>
		public const int Division = 25;

		/// <summary>
		/// The Assignment token ID.
		/// </summary>
		public const int Assignment = 26;

		/// <summary>
		/// The Equality token ID.
		/// </summary>
		public const int Equality = 27;

		/// <summary>
		/// The Inequality token ID.
		/// </summary>
		public const int Inequality = 28;

		/// <summary>
		/// The OperatorOrPunctuatorEnd token ID.
		/// </summary>
		public const int OperatorOrPunctuatorEnd = 29;

		/// <summary>
		/// The MaxTokenID token ID.
		/// </summary>
		public const int MaxTokenID = 30;

	}
	#endregion

	#region Lexical State IDs
	/// <summary>
	/// Contains the lexical state IDs for the <c>Simple</c> language.
	/// </summary>
	public class SimpleLexicalStateID {

		/// <summary>
		/// Returns the string-based key for the specified lexical state ID.
		/// </summary>
		/// <param name="id">The lexical state ID to examine.</param>
		public static string GetLexicalStateKey(int id) {
			System.Reflection.FieldInfo[] fields = typeof(SimpleLexicalStateID).GetFields();
			foreach (System.Reflection.FieldInfo field in fields) {
				if ((field.IsStatic) && (field.IsLiteral) && (id.Equals(field.GetValue(null))))
					return field.Name;
			}
			return null;
		}

		/// <summary>
		/// The Default lexical state ID.
		/// </summary>
		public const int Default = 0;

	}
	#endregion

	#region Semantic Parser
	/// <summary>
	/// Provides a semantic parser for the <c>Simple</c> language.
	/// </summary>
	internal class SimpleSemanticParser : ActiproSoftware.SyntaxEditor.ParserGenerator.RecursiveDescentSemanticParser {

		private CompilationUnit	compilationUnit;
		private System.Int32	curlyBraceLevel;

		/// <summary>
		/// Initializes a new instance of the <c>SimpleSemanticParser</c> class.
		/// </summary>
		/// <param name="lexicalParser">The <see cref="ActiproSoftware.SyntaxEditor.ParserGenerator.IRecursiveDescentLexicalParser"/> to use for lexical parsing.</param>
		public SimpleSemanticParser(ActiproSoftware.SyntaxEditor.ParserGenerator.IRecursiveDescentLexicalParser lexicalParser) : base(lexicalParser) {}
	
		/// <summary>
		/// Advances to the next <see cref="IToken"/>.
		/// </summary>
		/// <returns>
		/// The <see cref="IToken"/> that was read.
		/// </returns>
		protected override IToken AdvanceToNext() {
			IToken token = base.AdvanceToNext();
			if (!this.TokenIsLanguageChange(token)) {
				switch (token.ID) {
					case SimpleTokenID.OpenCurlyBrace:
						curlyBraceLevel++;
						break;
					case SimpleTokenID.CloseCurlyBrace:
						curlyBraceLevel--;
						break;
				}
			}
			return token;
		}

		/// <summary>
		/// Advances to (or past) the next matching close curly brace.
		/// </summary>
		/// <param name="movePast">Whether to move past the close curly brace.</param>
		/// <param name="openCurlyBraceLevel">The level of the open curly brace.</param>	
		private void AdvanceToNextCloseCurlyBrace(System.Int32 openCurlyBraceLevel, System.Boolean movePast) {
			while (!this.IsAtEnd) {
				this.AdvanceToNext(SimpleTokenID.OpenCurlyBrace, SimpleTokenID.CloseCurlyBrace); 
				if ((this.TokenIs(this.LookAheadToken, SimpleTokenID.CloseCurlyBrace)) && (curlyBraceLevel <= openCurlyBraceLevel + 1))
					break;
				this.AdvanceToNext();
			}			
			if ((movePast) && (this.TokenIs(this.LookAheadToken, SimpleTokenID.CloseCurlyBrace)))
				this.AdvanceToNext();
		}
	
		/// <summary>
		/// Gets the <see cref="CompilationUnit"/> that was parsed.
		/// </summary>
		/// <value>The <see cref="CompilationUnit"/> that was parsed.</value>
		public CompilationUnit CompilationUnit {
			get {
				return compilationUnit;
			}
		}
	
		/// <summary>
		/// Reports a syntax error.
		/// </summary>
		/// <param name="textRange">The <see cref="TextRange"/> of the error.</param>
		/// <param name="message">The error message.</param>
		protected override void ReportSyntaxError(TextRange textRange, System.String message) {
			// Don't allow multiple errors at the same offset
			if ((compilationUnit.SyntaxErrors.Count > 0) && (((SyntaxError)compilationUnit.SyntaxErrors[compilationUnit.SyntaxErrors.Count - 1]).TextRange.StartOffset == textRange.StartOffset))
				return;
			
			compilationUnit.SyntaxErrors.Add(new SyntaxError(textRange, message));
		}

		/// <summary>
		/// Parses the document and generates a document object model.
		/// </summary>
		public void Parse() {
			this.MatchCompilationUnit();
		}

		/// <summary>
		/// Matches a <c>CompilationUnit</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>CompilationUnit</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Function</c>.
		/// </remarks>
		protected virtual bool MatchCompilationUnit() {
			curlyBraceLevel = 0;
			compilationUnit = new CompilationUnit();
			compilationUnit.StartOffset = this.LookAheadToken.StartOffset;
			System.Boolean errorReported = false;
			while (!this.IsAtEnd) {
				if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Function)) {
					errorReported = false;
					while (this.TokenIs(this.LookAheadToken, SimpleTokenID.Function)) {
						this.MatchFunctionDeclaration();
					}
				}
				else {
					// Error recovery:  Advance to the next token since nothing was matched
					if (!errorReported) {
						this.ReportSyntaxError("Function declaration expected.");
						errorReported = true;
					}
					this.AdvanceToNext();
				}
			}
			compilationUnit.EndOffset = this.LookAheadToken.EndOffset;
			return true;
		}

		/// <summary>
		/// Matches a <c>FunctionDeclaration</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>FunctionDeclaration</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Function</c>.
		/// </remarks>
		protected virtual bool MatchFunctionDeclaration() {
			FunctionDeclaration functionDeclaration = new FunctionDeclaration();
			functionDeclaration.StartOffset = this.LookAheadToken.StartOffset;
			Identifier name;
			AstNodeList parameterList = null;
			Statement blockStatement;
			if (!this.Match(SimpleTokenID.Function))
				return false;
			if (!this.MatchIdentifier(out name))
				return false;
			if (!this.Match(SimpleTokenID.OpenParenthesis))
				return false;
			functionDeclaration.Name = name;
			compilationUnit.Functions.Add(functionDeclaration);
			if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Identifier)) {
				if (!this.MatchFunctionParameterList(out parameterList))
					return false;
			}
			this.Match(SimpleTokenID.CloseParenthesis);
			if (parameterList != null)
				functionDeclaration.Parameters.AddRange(parameterList.ToArray());
			functionDeclaration.BlockStartOffset = this.LookAheadToken.StartOffset;
			this.MatchBlock(out blockStatement);
			functionDeclaration.BlockStatement = (BlockStatement)blockStatement;
			functionDeclaration.BlockEndOffset = this.Token.EndOffset;
			functionDeclaration.EndOffset = this.Token.EndOffset;
			return true;
		}

		/// <summary>
		/// Matches a <c>Identifier</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>Identifier</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Identifier</c>.
		/// </remarks>
		protected virtual bool MatchIdentifier(out Identifier identifier) {
			identifier = null;
			if (!this.Match(SimpleTokenID.Identifier))
				return false;
			identifier = new Identifier(this.TokenText, this.Token.TextRange);
			return true;
		}

		/// <summary>
		/// Matches a <c>FunctionParameterList</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>FunctionParameterList</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Identifier</c>.
		/// </remarks>
		protected virtual bool MatchFunctionParameterList(out AstNodeList parameterList) {
			parameterList = new AstNodeList(null);
			Identifier parameterName;
			if (!this.MatchIdentifier(out parameterName))
				return false;
			else {
				parameterList.Add(parameterName);
			}
			while (this.TokenIs(this.LookAheadToken, SimpleTokenID.Comma)) {
				if (!this.Match(SimpleTokenID.Comma))
					return false;
				if (this.MatchIdentifier(out parameterName)) {
					parameterList.Add(parameterName);
				}
			}
			return true;
		}

		/// <summary>
		/// Matches a <c>Statement</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>Statement</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>Identifier</c>, <c>SemiColon</c>, <c>Var</c>, <c>Return</c>, <c>OpenCurlyBrace</c>.
		/// </remarks>
		protected virtual bool MatchStatement(out Statement statement) {
			statement = null;
			System.Int32 startOffset = this.LookAheadToken.StartOffset;
			if (this.TokenIs(this.LookAheadToken, SimpleTokenID.OpenCurlyBrace)) {
				if (!this.MatchBlock(out statement))
					return false;
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.SemiColon)) {
				// Empty statement
				if (!this.Match(SimpleTokenID.SemiColon))
					return false;
				statement = new EmptyStatement(this.Token.TextRange);
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Var)) {
				// Variable declaration statement
				Identifier variableName = null;
				if (!this.Match(SimpleTokenID.Var))
					return false;
				if (!this.MatchIdentifier(out variableName))
					return false;
				this.Match(SimpleTokenID.SemiColon);
				statement = new VariableDeclarationStatement(variableName, new TextRange(startOffset, this.Token.EndOffset));
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Identifier)) {
				// Assignment statement
				Identifier variableName = null;
				Expression expression = null;
				if (!this.MatchIdentifier(out variableName))
					return false;
				if (!this.Match(SimpleTokenID.Assignment))
					return false;
				if (!this.MatchExpression(out expression))
					return false;
				this.Match(SimpleTokenID.SemiColon);
				statement = new AssignmentStatement(variableName, expression, new TextRange(startOffset, this.Token.EndOffset));
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Return)) {
				// Return statement
				Expression expression = null;
				if (!this.Match(SimpleTokenID.Return))
					return false;
				if (!this.MatchExpression(out expression))
					return false;
				this.Match(SimpleTokenID.SemiColon);
				statement = new ReturnStatement(expression, new TextRange(startOffset, this.Token.EndOffset));
			}
			else
				return false;
			return true;
		}

		/// <summary>
		/// Matches a <c>Block</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>Block</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenCurlyBrace</c>.
		/// </remarks>
		protected virtual bool MatchBlock(out Statement block) {
			block = new BlockStatement();
			block.StartOffset = this.LookAheadToken.StartOffset;
			Statement statement;
			System.Int32 statementCurlyBraceLevel = curlyBraceLevel;
			if (!this.Match(SimpleTokenID.OpenCurlyBrace))
				return false;
			System.Boolean errorReported = false;
			while (!this.IsAtEnd) {
				if ((this.TokenIs(this.LookAheadToken, SimpleTokenID.CloseCurlyBrace)) && (curlyBraceLevel == statementCurlyBraceLevel + 1))
					break;
				else if (this.IsInMultiMatchSet(0, this.LookAheadToken)) {
					errorReported = false;
					while (this.IsInMultiMatchSet(1, this.LookAheadToken)) {
						if (!this.MatchStatement(out statement)) {
							if (!this.TokenIs(this.LookAheadToken, SimpleTokenID.CloseCurlyBrace)) this.AdvanceToNext();
						}
						else {
							((BlockStatement)block).Statements.Add(statement);
						}
					}
				}
				else {
					// Error recovery:  Advance to the next token since nothing was matched
					if (!errorReported) {
						this.ReportSyntaxError("Statement expected.");
						errorReported = true;
					}
					this.AdvanceToNext();
				}
			}
			this.Match(SimpleTokenID.CloseCurlyBrace);
			block.EndOffset = this.Token.EndOffset;
			return true;
		}

		/// <summary>
		/// Matches a <c>Expression</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>Expression</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchExpression(out Expression expression) {
			if (!this.MatchEqualityExpression(out expression))
				return false;
			return true;
		}

		/// <summary>
		/// Matches a <c>EqualityExpression</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>EqualityExpression</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchEqualityExpression(out Expression expression) {
			System.Int32 startOffset = this.LookAheadToken.StartOffset;
			Expression rightExpression;
			if (!this.MatchAdditiveExpression(out expression))
				return false;
			while ((this.TokenIs(this.LookAheadToken, SimpleTokenID.Equality)) || (this.TokenIs(this.LookAheadToken, SimpleTokenID.Inequality))) {
				OperatorType operatorType = OperatorType.None;
				if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Equality)) {
					if (!this.Match(SimpleTokenID.Equality))
						return false;
					else {
						operatorType = OperatorType.Equality;
					}
				}
				else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Inequality)) {
					if (!this.Match(SimpleTokenID.Inequality))
						return false;
					else {
						operatorType = OperatorType.Inequality;
					}
				}
				else
					return false;
				if (!this.MatchEqualityExpression(out rightExpression))
					return false;
				expression = new BinaryExpression(operatorType, expression, rightExpression, new TextRange(startOffset, this.Token.EndOffset));
			}
			return true;
		}

		/// <summary>
		/// Matches a <c>AdditiveExpression</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>AdditiveExpression</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchAdditiveExpression(out Expression expression) {
			System.Int32 startOffset = this.LookAheadToken.StartOffset;
			Expression rightExpression;
			if (!this.MatchMultiplicativeExpression(out expression))
				return false;
			while ((this.TokenIs(this.LookAheadToken, SimpleTokenID.Addition)) || (this.TokenIs(this.LookAheadToken, SimpleTokenID.Subtraction))) {
				OperatorType operatorType = OperatorType.None;
				if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Addition)) {
					if (!this.Match(SimpleTokenID.Addition))
						return false;
					else {
						operatorType = OperatorType.Addition;
					}
				}
				else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Subtraction)) {
					if (!this.Match(SimpleTokenID.Subtraction))
						return false;
					else {
						operatorType = OperatorType.Subtraction;
					}
				}
				else
					return false;
				if (!this.MatchAdditiveExpression(out rightExpression))
					return false;
				expression = new BinaryExpression(operatorType, expression, rightExpression, new TextRange(startOffset, this.Token.EndOffset));
			}
			return true;
		}

		/// <summary>
		/// Matches a <c>MultiplicativeExpression</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>MultiplicativeExpression</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchMultiplicativeExpression(out Expression expression) {
			System.Int32 startOffset = this.LookAheadToken.StartOffset;
			Expression rightExpression;
			if (!this.MatchPrimaryExpression(out expression))
				return false;
			while ((this.TokenIs(this.LookAheadToken, SimpleTokenID.Multiplication)) || (this.TokenIs(this.LookAheadToken, SimpleTokenID.Division))) {
				OperatorType operatorType = OperatorType.None;
				if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Multiplication)) {
					if (!this.Match(SimpleTokenID.Multiplication))
						return false;
					else {
						operatorType = OperatorType.Multiplication;
					}
				}
				else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Division)) {
					if (!this.Match(SimpleTokenID.Division))
						return false;
					else {
						operatorType = OperatorType.Division;
					}
				}
				else
					return false;
				if (!this.MatchMultiplicativeExpression(out rightExpression))
					return false;
				expression = new BinaryExpression(operatorType, expression, rightExpression, new TextRange(startOffset, this.Token.EndOffset));
			}
			return true;
		}

		/// <summary>
		/// Matches a <c>PrimaryExpression</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>PrimaryExpression</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchPrimaryExpression(out Expression expression) {
			expression = null;
			System.Int32 startOffset = this.LookAheadToken.StartOffset;
			if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Number)) {
				if (!this.Match(SimpleTokenID.Number))
					return false;
				else {
					expression = new NumberExpression(Convert.ToInt32(this.TokenText), this.Token.TextRange);
				}
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.Identifier)) {
				if (!this.Match(SimpleTokenID.Identifier))
					return false;
				// This shows one way to reduce grammar ambiguity
				if (!this.TokenIs(this.LookAheadToken, SimpleTokenID.OpenParenthesis)) {
					// The next token is not an open parenthesis... must be a simple name
					expression = new SimpleName(this.TokenText, this.Token.TextRange);
					return true;
				}
				
				expression = new FunctionAccessExpression(new Identifier(this.TokenText, this.Token.TextRange));
				AstNodeList argumentList = null;
				if (!this.Match(SimpleTokenID.OpenParenthesis))
					return false;
				if ((this.TokenIs(this.LookAheadToken, SimpleTokenID.OpenParenthesis)) || (this.TokenIs(this.LookAheadToken, SimpleTokenID.Identifier)) || (this.TokenIs(this.LookAheadToken, SimpleTokenID.Number))) {
					if (!this.MatchFunctionArgumentList(out argumentList))
						return false;
				}
				this.Match(SimpleTokenID.CloseParenthesis);
				if (argumentList != null)
					((FunctionAccessExpression)expression).Parameters.AddRange(argumentList.ToArray());
				expression.TextRange = new TextRange(startOffset, this.Token.EndOffset);
			}
			else if (this.TokenIs(this.LookAheadToken, SimpleTokenID.OpenParenthesis)) {
				if (!this.Match(SimpleTokenID.OpenParenthesis))
					return false;
				if (!this.MatchExpression(out expression))
					return false;
				if (!this.Match(SimpleTokenID.CloseParenthesis))
					return false;
				expression = new ParenthesizedExpression(expression, new TextRange(startOffset, this.Token.EndOffset));
			}
			else
				return false;
			return true;
		}

		/// <summary>
		/// Matches a <c>FunctionArgumentList</c> non-terminal.
		/// </summary>
		/// <returns><c>true</c> if the <c>FunctionArgumentList</c> was matched successfully; otherwise, <c>false</c>.</returns>
		/// <remarks>
		/// The non-terminal can start with: <c>OpenParenthesis</c>, <c>Identifier</c>, <c>Number</c>.
		/// </remarks>
		protected virtual bool MatchFunctionArgumentList(out AstNodeList argumentList) {
			argumentList = new AstNodeList(null);
			Expression argument;
			if (!this.MatchExpression(out argument))
				return false;
			else {
				argumentList.Add(argument);
			}
			while (this.TokenIs(this.LookAheadToken, SimpleTokenID.Comma)) {
				if (!this.Match(SimpleTokenID.Comma))
					return false;
				if (this.MatchExpression(out argument)) {
					argumentList.Add(argument);
				}
			}
			return true;
		}

		/// <summary>
		/// Gets the multi-match sets array.
		/// </summary>
		/// <value>The multi-match sets array.</value>
		protected override bool[,] MultiMatchSets {
			get {
				return multiMatchSets;
			}
		}

		private const bool Y = true;
		private const bool n = false;
		private static bool[,] multiMatchSets = {
			// 0: Identifier SemiColon Var Return OpenCurlyBrace 
			{n,n,n,n,n,n,n,n,n,Y,n,n,Y,Y,n,n,Y,n,n,n,n,Y,n,n,n,n,n,n,n,n,n},
			// 1: Identifier SemiColon Var Return OpenCurlyBrace 
			{n,n,n,n,n,n,n,n,n,Y,n,n,Y,Y,n,n,Y,n,n,n,n,Y,n,n,n,n,n,n,n,n,n}
		};

	}
	#endregion

}
